﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;

using iTool.Cloud.Database.ServiceProvider;

using Microsoft.Data.Sqlite;

namespace iTool.Cloud.Database
{
    internal static class iTransaction
    {
        const string DirectoryPath = "./Storage";
        const string DataSource = DirectoryPath + "/DataBase.master";
        static string SqliteConnectionInstanceOfPrivate;
        static Dictionary<long, SqliteConnection> Connections;
        static Dictionary<long, DbTransaction> Transactions;
        static iTransaction()
        {
            Transactions = new Dictionary<long, DbTransaction>();
            Connections = new Dictionary<long, SqliteConnection>();
            SqliteConnectionInstanceOfPrivate = new SqliteConnectionStringBuilder
            {
                DataSource = DataSource,
                Cache = SqliteCacheMode.Private,
                Pooling = true
            }.ToString();
        }

        static void Ini(long tranId)
        {
            if (!Connections.ContainsKey(tranId))
            {
                lock (Connections)
                {
                    var connection = new SqliteConnection(SqliteConnectionInstanceOfPrivate);
                    Connections.Add(tranId, connection);
                }
            }
        }

        public static async ValueTask BeginTransactionAsync(long tranId, bool isLockTableDB)
        {
            Ini(tranId);
            Connections[tranId].Open();
            var transaction = await Connections[tranId].BeginTransactionAsync(isLockTableDB ? System.Data.IsolationLevel.Serializable : System.Data.IsolationLevel.ReadUncommitted);
            if (Transactions.ContainsKey(tranId))
            {
                Transactions.Remove(tranId);
            }
            Transactions.Add(tranId, transaction);
        }

        public static async ValueTask CommitAsync(long tranId)
        {
            await Transactions[tranId].CommitAsync();
        }

        public static async ValueTask RollbackAsync(long tranId)
        {
            await Transactions[tranId].RollbackAsync();
        }

        public static async ValueTask DisposeAsync(long tranId)
        {
            if (Transactions.ContainsKey(tranId))
            {
                Transactions[tranId].Dispose();
                Transactions.Remove(tranId);
            }

            if (Connections.ContainsKey(tranId))
            {
                await Connections[tranId].CloseAsync();
                Connections.Remove(tranId);
            }
        }

        public static void CheckTransaction(long tranId)
        {
            if (!Transactions.ContainsKey(tranId) || !Connections.ContainsKey(tranId))
            {
                throw new Exception("Connection or Transaction is null");
            }
            if (Connections[tranId].State != System.Data.ConnectionState.Open)
            {
                throw new Exception("connection not is open");
            }
        }

        public static SqliteTransaction GetSqliteTransaction(long tranId)
        {
            return (SqliteTransaction)Transactions[tranId];
        }

        public static SqliteConnection GetConnection(long tranId)
        {
            return Connections[tranId];
        }

    }
}
